﻿
/*-------------------------------------------------
 *  
 * LiMeLanguage MainCode.
 * Latest Update 2011-05-02.
 * 
 * ...コメント処理の実装終了。
 * ...関数ごとに文をclassに分ける？
 * ...上記の案は決定事項なので、classの実装をする。
 * ...classの実装終了。
 * ...文法を明確に定義し、最適化処理を書く。
 * 
 * Edit By Swallow.
 * 
---------------------------------------------------*/



using System;
using System.Data;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Microsoft.VisualBasic;


#region テスト呼び出し
class Test
{
    static public void Main()
    {
        using (System.IO.StreamReader sr = new System.IO.StreamReader("test.ltm"))
        {
            LiMeLanguage tm = new LiMeLanguage(sr.ReadToEnd());

            Console.WriteLine("\nProcces Start... Press Any Key");
            Console.ReadLine();

            tm.MainProc();

            Console.WriteLine("\nProcces End... Press Any Key");
            Console.ReadLine();
        }
    }
}
#endregion



class LiMeLanguage
{
    #region コード系変数
    private string Code = "";//コード。こいつに最適化処理がコンストラクタでなされる。
    string[] SpaceSplit;//空白で分割したToken. Codeから分割される。
    private List<Expression> CodeTokens = new List<Expression>(); //文の区切りのList。SpaceSplitから文毎に分けられる。
    private List<Functions> CodeFunctions = new List<Functions>();//関数リスト。CodeTokensから関数別にリストに入る。
    private List<Class> CodeClass = new List<Class>();//クラスのリスト。コードの変数宣言と、CodeFunctionsからリストに入る。
    private System.Collections.Hashtable vars = new System.Collections.Hashtable(); //変数テーブル
    private Stack Args = new Stack();

    #endregion

    #region コンストラクタ&コメント処理
    public LiMeLanguage(string SourceCode)
    {
        Code = SourceCode;
        Literal.Move(ref Code);//リテラルの移動
        Code = Code.Replace("\t", " ");//タブ文字を削除
        Code = Regex.Replace(Code, "[ ]+", " ");//余分な空白の削除
        Init.Comment.DeleteComment(ref Code);//コメントの消去
        Code = Code.Replace(Environment.NewLine, "");//改行の削除

        Optimization.Proc(ref Code);//最適化処理
        
        /////////
        //一クラスずつ処理
        Regex mm = new Regex(@"##[A-Za-z_~]+##");//クラス用
        Code = mm.Replace(Code, @"###CLASS### $&");//クラス識別氏を付ける

        string[] Sp = Strings.Split(Code, "###CLASS###");//クラス別に分ける
        Code = "";//一旦空にしておく

        for (int i = 0; i < Sp.Length; i++)//クラス別に処理
        {
            Init.GetClass.GetClassMember(ref Sp[i], ref CodeClass);//クラス処理
            Code += Sp[i];
        }

        Code = Regex.Replace(Code, "[ ]+", " ");//処理によって生まれる余分な空白の削除


        SpaceSplit = Code.Split(' ');//空白で切り分ける。


        Literal.Undo(ref SpaceSplit);//リテラルの復元

        #region debug
#if DEBUG
        Console.Write("\n[InputCode-Optimization]");
        foreach (string temp in SpaceSplit)
        {
            Console.Write(" " + temp);
        }
#endif
        #endregion
    }

    
    #endregion

    #region Core(各関数呼び出し)
    public void MainProc()
    {
        if (Code == null){throw new NotCodeException("コードが空です。"); }
        SyntaxError.Init();//文法エラーの初期化
        this.Parse();//構文解析
        this.Exec();//実行
    }
    #endregion

    #region 構文解析
    private void Parse()
    {

        Split.Expressions.Split(ref Code, ref CodeTokens, SpaceSplit);// 文ごとにCodeTokensのListに入れる

        #region debug
#if DEBUG
        /*Debug*/
        Console.WriteLine("[Queue::Parse::Split::Step1]");
        int co = 0;
        foreach (Expression e in CodeTokens)
        {
            Console.WriteLine("\t[{0} - TokenList]", co);
            string[] debug = e.TokenList.ToArray();
            foreach (string d in debug)
            {
                Console.Write("\t\t" + d + "\n");
            }
            co++;
        }
#endif
        #endregion

        //Split.AtMark.Split(ref CodeTokens);//アットマークの切り分け(関数宣言記号)

        #region debug
#if DEBUG
        /*Debug*/
        Console.WriteLine("[Queue::Parse::Split::Step2]");
        int cosss = 0;
        foreach (Expression e in CodeTokens)
        {
            Console.WriteLine("\t[{0} - TokenList]", cosss);
            string[] debug = e.TokenList.ToArray();
            foreach (string d in debug)
            {
                Console.Write("\t\t" + d + "\n");
            }
            cosss++;
        }
#endif
        #endregion

        Split.Dollar.Split(ref CodeTokens);//ドルマークの切り分け(関数呼び出し記号)

        #region debug
        #if DEBUG
        Console.WriteLine("[Queue::Parse::Split::Step3]");
        cosss = 0;
        foreach (Expression e in CodeTokens)
        {
            Console.WriteLine("\t[{0} - TokenList]", cosss);
            string[] debug = e.TokenList.ToArray();
            foreach (string d in debug)
            {
                Console.Write("\t\t" + d + "\n");
            }
            cosss++;
        }
#endif
        #endregion

        Split.Function.Split(ref CodeFunctions, CodeTokens);//関数別に分ける
        Split.Args.Split(ref CodeFunctions);
        #region debug
#if DEBUG
        Console.WriteLine("[Queue::Parse::Split::Step4]");
        cosss = 0;
        foreach (Functions e in CodeFunctions)
        {
            Console.WriteLine("Name = " +e.Name);
            Console.WriteLine("Class = " + e.Class);
            Console.WriteLine("Access = " + e.AccessLevel);
            Console.Write("Args = ");
            foreach (string exp in e.ArgName.ToArray())
            {
                Console.WriteLine("\t" + exp);
            }

            string[] temp = e.Expression.ToArray();
            Console.Write("Main = ");
                foreach (string aaa in temp)
                {
                    Console.WriteLine("\t"+aaa);
                }

        }
#endif
        #endregion

        Split.Classer.Split(ref CodeClass, CodeFunctions);//クラス別に分ける

        #region debug
#if DEBUG
        Console.WriteLine("\n[Queue::Parse::Split::Step5]\n");

        foreach (Class c in CodeClass)
        {
            Console.WriteLine("ClassName = " + c.Name);
            Console.WriteLine("Constructor = ");

            foreach (Functions f in c.Constructor)
            {
                Console.WriteLine("\tFuncName = " + f.Name);
                Console.WriteLine("\tAccessLevel = " + f.AccessLevel + "\n");
                foreach (string s in f.Expression)
                {
                    Console.WriteLine("\t\t" + s);
                }

                Console.WriteLine("");
            }
            Console.WriteLine("Destructor = ");
            foreach (Functions f in c.Destructor)
            {
                Console.WriteLine("\tFuncName = " + f.Name);
                Console.WriteLine("\tAccessLevel = " + f.AccessLevel);
                foreach (string s in f.Expression)
                {
                    Console.WriteLine("\t\t" + s);
                }
                Console.WriteLine("");
            }
            Console.WriteLine("Functions = ");
            foreach (Functions f in c.Functions)
            {
                Console.WriteLine("\tFuncName = " + f.Name);
                Console.WriteLine("\tAccessLevel = " + f.AccessLevel);
                foreach (string s in f.Expression)
                {
                    Console.WriteLine("\t\t" + s);
                }
                Console.WriteLine("");
            }
            Console.WriteLine("");
        }
#endif
        #endregion

    }
    #endregion

    #region 実行部

    private void Exec()
    {
        Functions Main = this.GetMain();
        if (Main == null)//Main関数がなかったら
        {
            SyntaxError.Message(1);//MainNotFound
        }


        /////////////////////////
        //引数
        string[] argsname = Main.ArgName.ToArray();
        int argc = 0;
        foreach (string variable in Args.call())
        {
            vars[argsname[argc]] = variable;
            argc++;
        }
        Console.WriteLine("aa");
        //////////////////
        //処理
        Stack st = new Stack();
        int skip = 0; //先読みの場合があるのでそのカウンタ
        string value = ""; //定数項の場合の値
        int Exv = -1;//インデックス数
        foreach (string exp in Main.Expression)
        {

            if (skip != 0)//すでに読んでいる場合
            {
                skip--;
                continue;
            }

            if (exp != ";") //文の区切りでないなら
            {
                st.push(exp);//スタックに追加
            }

            else //文の区切りなら
            {
                string[] expr = st.call();//一文
                foreach (string expo in expr)//単語処理
                {
                    Exv++;
                    switch (expo)
                    {
                        case "print":
                            {
     
                                skip+=PrintConsole(Main.Expression[Exv+1],ref Exv);//表示処理
                               
                                break;
                            }
                        case "+": break;
                        case "-": break;
                        case "*": break;
                        case "/": break;
                        default: this.CheckValue(ref value, expo); break;
                    }
                }
            }
        }
    }
    #region 雑務
    private Functions GetMain()
    {
        Predicate<Class> cc = new Predicate<Class>(delegate(Class ccc) { bool fs = false; for (int i = 0; i < ccc.Functions.Count;i++ ) { if (ccc.Functions[i].Name == "Main") { fs = true; } } return fs; });
        Class Search;
        if ((Search = CodeClass.Find(cc)) != null)//Main関数を探す
        {
            

            foreach(Functions ff in Search.Functions)//Main関数を探す
            {
                if (ff.Name == "Main")
                {
                    return ff;
                }
            }

        }

        return null;
    }
    #endregion


    #region 定数項チェック
    private void CheckValue(ref string oldv, string newv)
    {
       
    }
    private int PrintConsole(string Text,ref int Exv)
    {
        int skip = 1;
        int pex = 2;
        Regex str = new Regex("^\".*?\"$");
        Regex numb = new Regex("^[0-9]*$");
        Predicate<Class> cc = new Predicate<Class>(delegate(Class ccc) { return ccc.Name == Text; });

        if (str.Match(Text).Success == true) //文字列なら
        {
            Console.WriteLine(Text);
        }
        else if(numb.Match(Text).Success == true) //数字なら
        {
            Console.WriteLine(Text);
        }
        else if(CodeClass.FindIndex(cc) != -1) //クラスなら
        {

        }
        
        Exv += pex;
        return skip;
    }
    #endregion

    #endregion

}
